// -*- Mode:go;  -*-

primary(base, system, provides) ::=
<<
<!
!-------------------------------------------------------------------------------------------------
! primary - main entry point for golang generator
!-------------------------------------------------------------------------------------------------
!
! This template is responsible for generating the primary golang stub that bridges between the
! Hyperledger fabric and chaincode.
!
!-------------------------------------------------------------------------------------------------
!>
/* Generated by chaintool.  DO NOT EDIT */

package ccs

import (
	"errors"
	"regexp"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"<base>/ccs/api"
)

type Interfaces map[string]interface{}
type Dispatchers map[string]api.Dispatcher

type stubHandler struct {
	initDispatcher api.Dispatcher
	dispatchers Dispatchers
}

var functionspec = regexp.MustCompile("([a-zA-Z0-9.]*)/fcn/([0-9]*)")

// Initialization function, called only once
func (self *stubHandler) Init(stub shim.ChaincodeStubInterface) pb.Response {

	args := stub.GetArgs()

	if len(args) != 2 {
		return shim.Error("Expected exactly two arguments")
	}

	function := string(args[0])

	if function != "init" {
		return shim.Error("Function must be \"init\"")
	}

	dispatcher := self.initDispatcher
	if dispatcher == nil {
		return shim.Error("Init interface not found: Please define \"appinit\"")
	}

	return dispatcher.Dispatch(stub, 1, args[1])
}

// Callback representing the invocation of a chaincode
func (self *stubHandler) Invoke(stub shim.ChaincodeStubInterface) pb.Response {

	args := stub.GetArgs()

	var params []byte

	if len(args) > 1 {
		params = args[1]
	}

	dispatcher, index, err := self.decodeFunction(string(args[0]))
	if err != nil {
		return shim.Error(err.Error())
	}

	return dispatcher.Dispatch(stub, index, params)
}

func (self *stubHandler) decodeFunction(function string) (api.Dispatcher, int, error) {

	spec := functionspec.FindAllStringSubmatch(function, -1)
	if spec == nil {
		return nil, 0, errors.New("Could not parse function name")
	}

	dispatcher, ok := self.dispatchers[spec[0][1]]
	if !ok {
		return nil, 0, errors.New("Interface not found")
	}

	index, err := strconv.Atoi(spec[0][2])
	if err != nil {
		return nil, 0, errors.New("Could not convert function index")
	}

	return dispatcher, index, nil
}

func (self *stubHandler) addDispatcher(name string, intf interface{}) error {

	dispatcher, err := api.Create(name, intf)
	if err != nil {
		return err
	}

	self.dispatchers[name] = dispatcher
	return nil
}

func New(interfaces Interfaces) (shim.Chaincode, error) {

	metadata := &ChaincodeMetaData{}
	handler := &stubHandler{dispatchers: make(Dispatchers)}

	// Install our metadata impl first so that we give the user a chance to subclass and override
	if err := handler.addDispatcher("org.hyperledger.chaintool.meta", metadata); err != nil {
		return nil, err
	}

	// Install all of the declared interfaces
	for name, intf := range interfaces {
		dispatcher, err := api.Create(name, intf)
		if err != nil {
			return nil, err
		}

		switch name {
		case "appinit":
			handler.initDispatcher = dispatcher
		default:
			handler.dispatchers[name] = dispatcher
		}
	}

	return handler, nil
}

<if(!system)>
func Start(interfaces Interfaces) error {

	handler, err := New(interfaces)
	if err != nil {
		return err
	}

	return shim.Start(handler)
}
<endif>

<!
!-------------------------------------------------------------------------------------------------
! end of primary template.
!-------------------------------------------------------------------------------------------------
!>
>>

api() ::=
<<
<!
!-------------------------------------------------------------------------------------------------
! api
!-------------------------------------------------------------------------------------------------
!
! This template defines an API between interface stubs and the common chaincode-support stub
!
!-------------------------------------------------------------------------------------------------
!>
/* Generated by chaintool.  DO NOT EDIT */

package api

import (
	"errors"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

type Dispatcher interface {
	Dispatch(stub shim.ChaincodeStubInterface, function int, params []byte) pb.Response
}

type Factory interface {
	Create(intf interface{}) (Dispatcher, error)
}

var factories = make(map[string]Factory)

func Register(name string, factory Factory) error {
	factories[name] = factory
	return nil
}

func Create(name string, intf interface{}) (Dispatcher, error) {
	factory, ok := factories[name]
	if !ok {
		return nil, errors.New("Factory not found")
	}

	return factory.Create(intf)
}
>>

metafact(fact) ::= "&meta.Facts_Fact{Name: \"<fact.name>\", Value: \"<fact.value>\"},"

metadata(facts, provides) ::=
<<
<!
!-------------------------------------------------------------------------------------------------
! metadata
!-------------------------------------------------------------------------------------------------
!
! This template defines our metadata interface, allowing clients to query us for things like
! a list of the interfaces we support
!
!-------------------------------------------------------------------------------------------------
!>
package ccs

import (
	"errors"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"hyperledger/cci/org/hyperledger/chaintool/meta"
)

var interfaces = map[string][]byte {
	<provides.values:{intf|"<intf.name>": []byte("<intf.bytes>"),}; separator="\n">
}

var facts = &meta.Facts {
	Facts: []*meta.Facts_Fact {
		<facts.values:{fact|<metafact(fact)>}; separator="\n">
	},
}

type ChaincodeMetaData struct {
}

func (self *ChaincodeMetaData) GetInterfaces(stub shim.ChaincodeStubInterface, params *meta.GetInterfacesParams) (*meta.Interfaces, error) {

	response := &meta.Interfaces{}
	for name, data := range interfaces {
		desc := &meta.InterfaceDescriptor{Name: name}

		if params.IncludeContent {
			desc.Data = data
		}

		response.Descriptors = append(response.Descriptors, desc)
	}

	return response, nil
}

func (self *ChaincodeMetaData) GetInterface(stub shim.ChaincodeStubInterface, params *meta.GetInterfaceParams) (*meta.InterfaceDescriptor, error) {

	intf, ok := interfaces[params.Name]
	if !ok {
		return nil, errors.New("Interface " + params.Name + " not found")
	}

	return &meta.InterfaceDescriptor{Data: intf}, nil
}

func (self *ChaincodeMetaData) GetFacts(stub shim.ChaincodeStubInterface, params *meta.GetFactsParams) (*meta.Facts, error) {

	return facts, nil
}
>>

server(base, intf) ::=
<<
<!
!-------------------------------------------------------------------------------------------------
! server
!-------------------------------------------------------------------------------------------------
!
! This template is responsible for generating the interface-specific golang provider stub
!
!-------------------------------------------------------------------------------------------------
!>
/* Generated by chaintool.  DO NOT EDIT */

package <intf.package>

import (
	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"<base>/ccs/api"
	"fmt"
)

type CCInterface interface {
	<declarefunctions(intf, intf.functions)>
}


type stubImpl struct {
	intf CCInterface
}

// Factory mechanics
type factoryImpl struct {
}

func init() {
	self := &factoryImpl{}
	api.Register("<intf.name>", self)
}

func (self *factoryImpl) Create(intf interface{}) (api.Dispatcher, error) {
	return &stubImpl{intf: intf.(CCInterface)}, nil
}

func (self *stubImpl) Dispatch(stub shim.ChaincodeStubInterface, function int, params []byte) pb.Response {
	// Handle different functions
	switch {
	<dispatchfunctions(intf, intf.functions)>
	default:
		return shim.Error("Received unknown function invocation")
	}
}

/* Server stubs */
<implementservers(intf, intf.functions)>

<!
!-------------------------------------------------------------------------------------------------
! end of server template.
!-------------------------------------------------------------------------------------------------
!>
>>

client(base, intf) ::=
<<
<!
!-------------------------------------------------------------------------------------------------
! client
!-------------------------------------------------------------------------------------------------
!
! This template is responsible for generating the interface-specific golang consumer stub
!
!-------------------------------------------------------------------------------------------------
!>
/* Generated by chaintool.  DO NOT EDIT */

package <intf.package>

import (
	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"fmt"
)

/* Client stubs */
<implementclients(intf, intf.functions)>

<!
!-------------------------------------------------------------------------------------------------
! end of client template.
!-------------------------------------------------------------------------------------------------
!>
>>

compositename(intf, func)          ::= "\"<intf.name>/fcn/<func.index>\""
implementservers(intf, functions)  ::= "<functions.values:{x | <implementserver(intf, x)> }; separator=\"\n\">"
implementclients(intf, functions)  ::= "<functions.values:{x | <implementclient(intf, x)> }; separator=\"\n\">"
dispatchfunctions(intf, functions) ::= "<functions.values:{x | <dispatchfunction(intf, x)> }; separator=\"\n\">"

declarefunctions(intf, functions) ::=
<<
<functions.values:{x | <x.name>(shim.ChaincodeStubInterface<if(x.param)>, *<x.param><endif>) <if(x.rettype)>(*<x.rettype>, error)<else>error<endif> }; separator="\n">
>>

dispatchfunction(intf, func) ::=
<<
case function == <func.index>:
	return self.proxy<func.name>(stub, params)
>>

implementserver(intf, func) ::=
<<

func (self *stubImpl) proxy<func.name>(stub shim.ChaincodeStubInterface, _params []byte) pb.Response {

	var err error;

	<if(func.param)>
	params := &<func.param>{}
	err = proto.Unmarshal(_params, params)
	if (err != nil) {
		return shim.Error(fmt.Sprintf("protobuf unmarshal error: %s", err))
	}
	<endif>

	<if(func.rettype)>result, err := <else>err = <endif>self.intf.<func.name>(stub<if(func.param)>, params<endif>)
	if (err != nil) {
		return shim.Error(err.Error())
	}

	<if(func.rettype)>
	_result, err := proto.Marshal(result)
	if (err != nil) {
		return shim.Error(fmt.Sprintf("protobuf marshal error: %s", err))
	}
	return shim.Success(_result)
	<else>
	return shim.Success(nil)
	<endif>
}

>>

implementclient(intf, func) ::=
<<

func <func.name>(stub shim.ChaincodeStubInterface, chaincodeName string<if(func.param)>, params *<func.param><endif>) <\\>
<if(func.rettype)>(*<func.rettype>, error)<else>error<endif> {

	<if(func.param)>
	args := make([][]byte, 2)
	<else>
	args := make([][]byte, 1)
	<endif>
	var err error

	args[0] = []byte(<compositename(intf, func)>)

	<if(func.param)>
	args[1], err = proto.Marshal(params)
	if (err != nil) {
		return <if(func.rettype)>nil, <endif>err
	}
	<endif>

	resp := stub.InvokeChaincode(chaincodeName, args, "")
	if resp.Status \< shim.ERROR {
		<if(func.rettype)>
		result := &<func.rettype>{}
		err = proto.Unmarshal(resp.Payload, result)
		if (err != nil) {
			return nil, fmt.Errorf("Error unmarshalling return value: %s", err)
		}
		return result, nil
		<else>
		return nil
		<endif>
	}

	return <if(func.rettype)>nil, <endif>fmt.Errorf("RPC failure: %s", resp.Message)
}

>>
